#include "menu.hh"

Menu::Menu ()
  : size_ (100, 100)
  , pos_ (0, 0)
  , is_active_ (false)
  , size_max_ (0, 0)
  , hoover_ (false)
  , tex_ (ContentHandler::get ()->texture ("menu"))
{}

Menu::Menu (Vector2d pos, Vector2d size)
  : size_ (size)
  , pos_ (pos)
  , is_active_ (false)
  , size_max_ (0, 0)
  , hoover_ (false)
  , tex_ (ContentHandler::get ()->texture ("menu"))
{}

bool
Menu::on_hoover (Vector2d cursor)
{
  // si le menu est actif et que le curseur est a l'interieur
  if (is_active_ &&
      cursor (0) >= pos_ (0) && cursor (0) < pos_ (0) + size_ (0) &&
      cursor (1) >= pos_ (1) && cursor (1) < pos_ (1) + size_ (1))
    {
      hoover_action (cursor); // on dit au menu courant que le curseur est sur lui
      hoover_ = true;
      return true;
    }

  hoover_ = false;
  return false;
}

void
Menu::on_click (Vector2d cursor, unsigned int button_id)
{
  if (is_active_ &&
      cursor (0) >= pos_ (0) && cursor (0) < pos_ (0) + size_ (0) &&
      cursor (1) >= pos_ (1) && cursor (1) < pos_ (1) + size_ (1))
    click_action (cursor, button_id); // on dit au menu courant que le click est sur lui
}

void
Menu::on_release (Vector2d cursor, unsigned int button_id)
{
  (void) cursor;
  (void) button_id;
}

// *** container *** //

Container::Container ()
  : Menu ()
{}

Container::Container (Vector2d pos, Vector2d size)
  : Menu (pos, size)
  , grid_ (0)
  , nb_x (0)
  , nb_y (0)
{}

Container::~Container ()
{
  Vector2d size_block (100 / nb_x, 100 / nb_y);

  // pour toutes les cases de ce menu
  for (int i = 0; i < nb_x; ++i)
    for (int j = 0; j < nb_y; ++j)
      if (grid_[i][j] != 0) // si la case est non vide
	{

	  Vector2d pos = grid_[i][j]->pos_get ();
	  Vector2d size = grid_[i][j]->size_get ();
	  // on met a 0 toutes les cases du meme objet (si il en fait plusieurs)
	  for (int x = i; x <= (pos (0) + size (0)) / size_block (0); ++x)
	    for (int y = j; y <= (pos (1) + size (1)) / size_block (1); ++y)
	      grid_[x][y] = 0;

	  // et on detruit le sous menu
	  delete grid_[i][j];
	}
}

bool
Container::on_hoover (Vector2d cursor)
{
  // si le menu est actif et que le curseur est a l'interieur
  if (is_active_ &&
      cursor (0) >= pos_ (0) && cursor (0) < pos_ (0) + size_ (0) &&
      cursor (1) >= pos_ (1) && cursor (1) < pos_ (1) + size_ (1))
    {
      hoover_action (cursor); // on dit au menu courant que le curseur est sur lui
      hoover_ = true;
      return true;
    }
  for (int i = 0; i < nb_x; ++i)
    for (int j = 0; j < nb_y; ++j)
      if (grid_[i][j])
	grid_[i][j]->hoover (false);

  hoover_ = false;
  return false;
}

void
Container::set_coord (Vector2d base, Vector2d size_max)
{
  size_max_ = size_max;

  Vector2d cur_size (size_max (0) * size_ (0) / 100,
		     size_max (1) * size_ (1) / 100);
  Vector2d tmp (base (0) + pos_ (0) * size_max_ (0) / 100,
		base (1) + pos_ (1) * size_max_ (1) / 100);
  Vector2d end (tmp (0) + size_ (0) * size_max_ (0) / 100,
		tmp (1) + size_ (1) * size_max_ (1) / 100);
  base_ = tmp;
  end_ = end;

  for (int i = 0; i < nb_x; ++i)
    for (int j = 0; j < nb_y; ++j)
      if (grid_[i][j])
	grid_[i][j]->set_coord (base_, cur_size);
}

void
Container::size_max_set (Vector2d size_max)
{
  size_max_ = size_max;
  Vector2d cur_size (size_max (0) * size_ (0) / 100,
		     size_max (1) * size_ (1) / 100);

  Vector2d base (pos_ (0) * size_max_ (0) / 100,
		 pos_ (1) * size_max_ (1) / 100);
  Vector2d end ((pos_ (0) + size_ (0)) * size_max_ (0) / 100,
		(pos_ (0) + size_ (0)) * size_max_ (1) / 100);

  base_ = base;
  end_ = end;
  if (grid_)
    {
      for (int i = 0; i < nb_x; ++i)
	for (int j = 0; j < nb_y; ++j)
	  if (grid_[i][j])
	    grid_[i][j]->size_max_set (cur_size);
    }
}

void
Container::set_grid (int nb_block_x, int nb_block_y)
{
  nb_x = nb_block_x;
  nb_y = nb_block_y;

  grid_ = new Menu**[nb_x];
  for (int i = 0; i < nb_x; ++i)
    {
      grid_[i] = new Menu*[nb_y];
      for (int j = 0; j < nb_y; ++j)
	grid_[i][j] = 0;
    }
}

bool
Container::add_menu (Menu* m)
{
  Vector2d m_size = m->size_get ();
  Vector2d m_pos = m->pos_get ();

  // on verifie que le menu ne sort pas du container
  assert (m_pos (0) >= 0 && m_pos (1) >= 0 &&
	  m_pos (0) + m_size (0) <= 100 &&
	  m_pos (1) + m_size (1) <= 100);

  Vector2d size_block (100 / nb_x, 100 / nb_y);

  // on teste tous les blocks ou on va devoir ajouter l'objet
  for (int i = m_pos (0) / size_block (0); i <= (m_pos (0) + m_size (0) - 1) / size_block (0); ++i)
    for (int j = m_pos (1) / size_block (1); j <= (m_pos (1) + m_size (1) - 1) / size_block (1); ++j)
      if (grid_[i][j])
	return false;

  // si aucun block n'etait rempli
  for (int i = m_pos (0) / size_block (0); i <= (m_pos (0) + m_size (0) - 1) / size_block (0); ++i)
    for (int j = m_pos (1) / size_block (1); j <= (m_pos (1) + m_size (1) - 1) / size_block (1); ++j)
	grid_[i][j] = m;
  return true;
}

void
Container::hoover_action (Vector2d cursor)
{
  // on fait l'action pour le container
  if (grid_)
    {
      Vector2d new_cursor (cursor (0) * 100 / size_ (0) - ((100 * pos_ (0)) / size_ (0)),
			   cursor (1) * 100 / size_ (1) - ((100 * pos_ (1)) / size_ (1)));

      Vector2d size_block (100 / nb_x, 100 / nb_y);
      Vector2d block_id (new_cursor (0) / size_block (0), new_cursor (1) / size_block (1));

      Menu* son = grid_[block_id (0)][block_id (1)];

	  for (int i = 0; i < nb_x; ++i)
	    for (int j = 0; j < nb_y; ++j)
	      if (grid_[i][j])
		grid_[i][j]->hoover (false);
      // TODO: voir si on hoover s'applique sur toutes l'arborescence ou juste le plus petit fils
      if (son) // si j'ai un fils a l'endroit du click je lui transmet
	{
	  son->on_hoover (new_cursor);
	}
      else // sinon je prends l'input pour moi
	{
	}
    }
}

void
Container::click_action (Vector2d cursor, unsigned int button_id)
{
  if (grid_)
    {
      Vector2d new_cursor (cursor (0) * 100 / size_ (0) - ((100 * pos_ (0)) / size_ (0)),
  			   cursor (1) * 100 / size_ (1) - ((100 * pos_ (1)) / size_ (1)));

      Vector2d size_block (100 / nb_x, 100 / nb_y);
      Vector2d block_id (new_cursor (0) / size_block (0), new_cursor (1) / size_block (1));

      Menu* son = grid_[block_id (0)][block_id (1)];

      if (son) // si j'ai un fils a l'endroit du click je lui transmet
  	son->on_click (new_cursor, button_id);
      else // sinon je prends l'input pour moi
  	{
  	}
    }
}

void
Container::dispatch () const
{
  glBindTexture(GL_TEXTURE_2D, tex_->id ());

  glBegin(GL_QUADS);
  if (hoover_)
    glColor3ub(255,255,255);
  else
    glColor3ub(150,150,150);
  glTexCoord2d (0, 1); glVertex2d(base_ (0), base_ (1));
  glTexCoord2d (0, 0); glVertex2d(base_ (0), end_ (1));
  glTexCoord2d (1, 0); glVertex2d(end_ (0), end_ (1));
  glTexCoord2d (1, 1); glVertex2d(end_ (0), base_ (1));
  glEnd();

  glBindTexture (GL_TEXTURE_2D, 0);

  for (int i = 0; i < nb_x; ++i)
    for (int j = 0; j < nb_y; ++j)
      if (grid_[i][j])
	grid_[i][j]->dispatch ();
}

// *** Button *** //

Button::Button ()
  : Menu ()
  , data_ (0)
{}

Button::Button (Vector2d pos, Vector2d size)
  : Menu (pos, size)
  , data_ (0)
{}

Button::~Button ()
{}

void
Button::hoover_action (Vector2d cursor)
{
  (void) cursor;
}

void
Button::click_action (Vector2d cursor, unsigned int button_id)
{
  (void) cursor;
  std::cout << button_id << std::endl;
}

void
Button::dispatch () const
{
  glBindTexture(GL_TEXTURE_2D, tex_->id ());

  glBegin(GL_QUADS);
  if (hoover_)
    glColor3ub(255,255,0);
  else
    glColor3ub(150,150,0);
  glTexCoord2d (0, 1); glVertex2d(base_ (0), base_ (1));
  glTexCoord2d (0, 0); glVertex2d(base_ (0), end_ (1));
  glTexCoord2d (1, 0); glVertex2d(end_ (0), end_ (1));
  glTexCoord2d (1, 1); glVertex2d(end_ (0), base_ (1));
  glEnd();

  glBindTexture (GL_TEXTURE_2D, 0);
}
